package algorithms.doubleClustering;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import algorithms.distanceFunctions.Distance;
import dataSet.Membership;
import dataSet.Nop;
import dataSet.Topic;

public class DoubleClustering
{
	private List<Nop>			newNopList;
	private List<Nop>			nopList;
	private List<Nop>			centersList;
	private List<Membership>	membershipOfNop;
	private Set<Topic>			topicList;
	private int					clustersNumber;
	private Double				m;					// fuzzyFactor

	public void initialize(List<Nop> nopList, List<Nop> newNopList, List<Nop> centersList)
	{
		this.nopList = nopList;
		this.newNopList = newNopList;
		this.centersList = centersList;
		clustersNumber = centersList.size();
		topicList = this.nopList.get(0).getTopicWeightMap().keySet();
	}

	public void mainProcess()
	{
		for (Nop aNop : this.newNopList)
		{
			addNop(aNop);
		}
	}

	public void addNop(Nop aNop)
	{
		Nop center = findClosetCenter(aNop);
		addMembership(aNop, center);
		updateCenters();
	}

	public void updateCenters()
	{
		// sum of u(ij)^m
		Double sumOfMembership = 0.0;
		// sum of u(ij)^m * x(i)
		Double sumOfValue;
		// new center : sumOfValue / sumOfMembership
		Nop tempNop;
		for (Nop aNop : this.nopList)
		{
			for (Nop aCenter : this.centersList)
			{
				int indexOfMembership = this.findMembership(aNop, aCenter);
				if (!(indexOfMembership == -1))
				{
					sumOfMembership += Math.pow(this.membershipOfNop.get(indexOfMembership).getMembershipValue(), m);
				}
			}
		}
		System.out.println("sumOfMembership " + sumOfMembership);
		//

		for (Nop aCenter : this.centersList)
		{
			tempNop = new Nop();
			for (Topic aTopic : this.topicList)
			{
				tempNop.setTopicWeightMap(aTopic, 0.0);
			}
			for (Topic aTopic : topicList)
			{
				sumOfValue = 0.0;
				for (Nop aNop : this.nopList)
				{
					int indexOfMembership = this.findMembership(aNop, aCenter);
					if (!(indexOfMembership == -1))
					{

						double u = this.membershipOfNop.get(indexOfMembership).getMembershipValue();
						double x = aNop.getTopicWeight(aTopic);
						double temp = Math.pow(u, m) * x;

						sumOfValue += temp;

					}
					else
					{
						System.out.println("----------error-----------");
					}
				}
				System.out.println("sumOfValue " + sumOfValue);
				double newWeight = sumOfValue / sumOfMembership;
				tempNop.setTopicWeightMap(aTopic, newWeight);
			}
			for (Topic aTopic : this.topicList)
			{
				double newWeight = tempNop.getTopicWeight(aTopic);
				aCenter.setTopicWeightMap(aTopic, newWeight);
			}
		}
	}

	public Nop findClosetCenter(Nop aNop)
	{
		double distance = 0.0;
		double temp = 0.0;
		int id = this.clustersNumber;
		;
		for (Nop center : this.centersList)
		{
			distance = Distance.euclideanDistance(aNop, center);
			temp = distance;
			if (temp > distance)
			{
				temp = distance;
				id = center.getId();
			}
		}
		return findCenterById(id);
	}

	private Nop findCenterById(int id)
	{
		Nop center = null;
		for (Nop aCenter : this.centersList)
		{
			if (aCenter.getId() == id) center = aCenter;
		}
		return center;
	}

	public void removeNop(Nop aNop)
	{
		ArrayList<Integer> indexList = new ArrayList<Integer>();
		for (Membership aMembership : this.membershipOfNop)
		{
			if (aMembership.getNop() == aNop)
			{
				indexList.add((Integer) this.membershipOfNop.indexOf(aMembership));
			}
		}
		for (Integer index : indexList)
		{
			this.membershipOfNop.remove(index);
		}
	}

	public void addMembership(Nop aNop, Nop center)
	{
		Membership membership = new Membership();
		membership.setCenter(center);
		membership.setNop(aNop);
		membership.setMembershipValue(1.0);
		this.membershipOfNop.add(membership);
		for (Nop aCenter : this.centersList)
		{
			membership = new Membership();
			membership.setCenter(aCenter);
			membership.setNop(aNop);
			membership.setMembershipValue(0.0);
			this.membershipOfNop.add(membership);
		}
	}

	public void createCluster()
	{
		//
	}

	public int findMembership(Nop aNop, Nop aCenter)
	{
		for (Membership aMembership : this.membershipOfNop)
		{
			if ((aMembership.getNop() == aNop) && (aMembership.getCenter() == aCenter)) { return this.membershipOfNop.indexOf(aMembership); }
		}
		return -1;
	}
}
